// Copyright 2007 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lichen.services.forum.impl;

import java.util.List;

import lichen.entities.forum.Treeable;
import lichen.services.ClazzUtils;
import lichen.services.HibernateUtils;
import lichen.services.forum.ForumClassService;
import lichen.services.forum.IMoveTreeNodeProcessor;

import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;

/**
 * 提供了对tee组件的操作服务类.
 * 
 * TODO :有一个比较大的问题就是怎么锁定表？？？
 * 
 * @author <a href="mailto:jun.tsai@gmail.com">Jun Tsai</a>
 * @version $Revision: 5 $
 * @since 0.2.1
 */
public class ForumClassServiceImpl implements ForumClassService {

	private Session session;

	public ForumClassServiceImpl(Session session) {
		this.session = session;
	}

	// 查询所有节点数量
	private static final String COUNT_ALL_NODE_HSQL = "select count(*) from %s  t ";

	// 删除节点
	private static final String DELETE_NODE_HSQL = "delete %s n where (n.left between ? and ? ) ";

	// 更新左边节点
	private static final String UPDATE_LEFT_HSQL = "update %s n set n.left=n.left+%d where n.left>? ";

	// 更新右边节点
	private static final String UPDATE_RIGHT_HSQL = "update %s n set n.right=n.right+%d where n.right>?";

	/**
	 * @see lichen.services.forum.ForumClassService#saveTreeChildNode(lichen.entities.forum.Treeable, lichen.entities.forum.Treeable, java.lang.Class)
	 */
	public void saveTreeChildNode(Treeable node, Treeable parentNode,
			Class clazz) {
		String treeClassName = getTreeClassName(node, clazz);

		if (parentNode == null) { // 插入顶级节点
			parentNode = (Treeable) ClazzUtils.newInstance(treeClassName);
			parentNode.setLeft(0);
			parentNode.setDepth(0);
			long rowCount = (Long) session.createQuery(
					String.format(COUNT_ALL_NODE_HSQL, treeClassName)).list()
					.iterator().next();
			parentNode.setRight((int) (rowCount * 2 + 1));
		} else { // reload parent object
			session.refresh(parentNode);
		}
		// 得到父节点的右边值
		int parentRight = parentNode.getRight();
		// 更新大于节点的值
		/*
		 * update table set left=left+2 where left>parentRight update table set
		 * right=right+2 where right>=parentRight
		 */

		String updateLeftHQL = String
				.format(UPDATE_LEFT_HSQL, treeClassName, 2);
		HibernateUtils.executeUpdate(session, updateLeftHQL, parentRight);

		String updateRightHQL = String.format(UPDATE_RIGHT_HSQL, treeClassName,
				2);
		HibernateUtils.executeUpdate(session, updateRightHQL, parentRight - 1);

		// 更新当前节点的值
		node.setLeft(parentRight);
		node.setRight(parentRight + 1);
		node.setDepth(parentNode.getDepth() + 1);

		// 保存当前的实体
		session.saveOrUpdate(node);
		if (parentNode.getId() != null) {
			session.refresh(parentNode);
		}
	}

	/**
	 * @see lichen.services.forum.ForumClassService#getTree(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	public List<? extends Treeable> getTree(Class<? extends Treeable> clazz) {
		DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
		criteria.addOrder(Order.asc("left"));
		return criteria.getExecutableCriteria(session).list();
	}

	/**
	 * @see lichen.services.forum.ForumClassService#moveNode(lichen.entities.forum.Treeable, int, java.lang.Class)
	 */
	public void moveNode(Treeable node, int n, Class clazz) {
		if (n == 0) {
			return;
		}

		IMoveTreeNodeProcessor processor = createSubProcessor(node, session, n);

		processor.execute(node, session, n, clazz);

	}

	private IMoveTreeNodeProcessor createSubProcessor(Treeable node,
			Session ht, int n) {
		if (n > 0) {
			return new MoveUpProcessor();
		} else {
			return new MoveDownProcessor();
		}

	}

	private String getTreeClassName(Treeable node, Class clazz) {
		if (clazz != null) {
			return clazz.getName();
		} else {
			return ClazzUtils.getEntityClass(node).getName();
		}
	}

	/**
	 * @see lichen.services.forum.ForumClassService#deleteTreeNode(lichen.entities.forum.Treeable, java.lang.Class)
	 */
	public void deleteTreeNode(Treeable node, Class clazz) {

		String treeClassName = getTreeClassName(node, clazz);
		int left = node.getLeft();
		int right = node.getRight();

		int width = left - right - 1;

		// 删除该节点，以及节点下面所属的字节点

		HibernateUtils.executeUpdate(session, String.format(DELETE_NODE_HSQL,
				treeClassName), left, right);

		// 更新其他节点的左右值
		HibernateUtils.executeUpdate(session, String.format(UPDATE_LEFT_HSQL,
				treeClassName, width), right);
		HibernateUtils.executeUpdate(session, String.format(UPDATE_RIGHT_HSQL,
				treeClassName, width), right);

	}
}

